
let middlewares=[
    async (ctx,next)=>{
        console.log('Start:',1);
         next();
        console.log('End:',1);
    },
    async (ctx,next)=>{
        console.log('Start:',2);
         next();
        console.log('End:',2);
    },
    async (ctx,next)=>{
        console.log('Start:',3);
         next();
        console.log('End:',3);
    }
];


(async ()=>{
    let fn=compose(middlewares);
    console.log(fn);
    fn('ctx').then(ret=>{
        console.log('ret:',ret);
    }).catch(err=>console.error('ERROR:',err));
})();

function compose(middlewares) {

    return (ctx)=>{
        let index=-1;
        return dispatch(0);

        function dispatch(i) {
            if (i <= index) return Promise.reject(new Error('next() called multiple times'))
            index=i;
            let fn=middlewares[i];
            if(!fn)return Promise.resolve();

            try{
                return Promise.resolve(fn(ctx,()=>{
                    return dispatch(i+1);
                }));
            }catch(err){
                return Promise.reject(err);
            }
        }
    }

}